/***********************************************************************************************************************
*                                                                                                                      *
* SPLASH build system v0.1                                                                                             *
*                                                                                                                      *
* Copyright (c) 2013 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                                 *
*                                                                                                                      *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                        *
*                                                                                                                      *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                           *
*                                                                                                                      *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                                                      *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                                                      *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                          *
*                                                                                                                      *
***********************************************************************************************************************/

#include "splashcore.h"

using namespace std;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

RoutedNCDNetlistNode::RoutedNCDNetlistNode(
	BuildGraph* graph,
	UnroutedNCDNetlistNode* netlist,
	FPGAPlaceAndRouteFlagList flags,
	XilinxFPGAToolchain* toolchain)
	: BuildGraphNode(graph)
	, m_netlist(netlist)
	, m_flags(flags)
	, m_toolchain(toolchain)
{
	m_name = netlist->GetName();
	m_device = netlist->GetDevice();
}

RoutedNCDNetlistNode::~RoutedNCDNetlistNode()
{
	
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Factory method

RoutedNCDNetlistNode* RoutedNCDNetlistNode::CreateRoutedNCDNetlistNode(
		BuildGraph* graph,
		UnroutedNCDNetlistNode* netlist,
		FPGAPlaceAndRouteFlagList flags,
		XilinxFPGAToolchain* toolchain)
{
	//Create the netlist node
	RoutedNCDNetlistNode* node = new RoutedNCDNetlistNode(graph, netlist, flags, toolchain);
	graph->AddNode(node);
	
	//Done
	return node;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Accessors

string RoutedNCDNetlistNode::GetOutputPath()
{
	string hash = GetHashCached();
	string outdir = m_graph->GetMetaDir() + "/" + hash;
	return outdir + "/" + m_name + ".ncd";
}

string RoutedNCDNetlistNode::GetDescription()
{
	char desc[1024];
	snprintf(desc, sizeof(desc), "Routed NCD netlist %s", m_name.c_str());
	return string(desc);
}

string RoutedNCDNetlistNode::GetBinaryPath()
{
	return GetOutputPath();
}

bool RoutedNCDNetlistNode::GetFilteredOutput(std::vector<std::string>& output)
{
	static const char* whitelist[]=
	{
		"ERROR",
		"error",
		"WARNING",
		"warning"
	};
	
	static const char* blacklist[]=
	{
		"Number of error messages:",
		"Number of warning messages:",
		"Completed - No errors found.",
		"WARNING:Par:283",					//Loadless signals, kinda obvious if we get this
		"WARNING:Par:545",					//Multithreading not supported if no timing constraints
		"WARNING:Timing:3223",				//Timing constraint ignored (empty time group, etc)
		"RAMD_D1_O has no load"				//RAM32M with unused output
	};
	
	return BuildGraphNode::GetFilteredOutput(
		output,
		whitelist,
		sizeof(whitelist)/sizeof(whitelist[0]),
		blacklist,
		sizeof(blacklist)/sizeof(blacklist[0])
		);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Building

void RoutedNCDNetlistNode::UpdateDependencies()
{
	m_dependencies.clear();
	m_dependencies.push_back(m_netlist);
}

string RoutedNCDNetlistNode::GetHash()
{	
	DebugPrintfHeading(5, "RoutedNCDNetlistNode::GetHash() [node = \"%s\"]\n", m_name.c_str());
	string hashin = "";
	
	//Update our dependencies
	UpdateDependencies();

	//Add data at this node
	hashin += sha256(m_name);
	hashin += m_toolchain->GetHash();
	if(m_flags.size())
		FatalError("RoutedNCDNetlistNode::GetHash() does not handle flags yet\n");
		
	//Add data for our dependencies
	for(size_t i=0; i<m_dependencies.size(); i++)
		hashin += m_dependencies[i]->GetHashCached(); 
	
	return sha256(hashin);
}

void RoutedNCDNetlistNode::Update(Cluster* cluster)
{
	//Rebuild all of our dependencies if necessary
	vector<ClusterJob*> deps;
	for(size_t i=0; i<m_dependencies.size(); i++)
	{		
		BuildGraphNode* node = m_dependencies[i];
		node->UpdateCached(cluster);
		if(node->GetBuildJob() != NULL)
			deps.push_back(node->GetBuildJob());
	}

	//Generate the PCF filename
	string netlist = m_netlist->GetBinaryPath();
	string dir = GetDirOfFile(netlist);
	string base = GetBasenameOfFileWithoutExt(netlist);
	string pcf = dir + "/" + base + ".pcf";

	//Run the actual place-and-route step
	m_job = m_toolchain->PlaceAndRouteNetlist(
		netlist,
		pcf,
		GetBinaryPath(),
		m_device,
		deps,
		m_flags,
		cluster);
}

